unit DragSignal;

interface

uses Windows, Classes, Controls, Graphics, StdCtrls, Messages, ExtCtrls, Menus, MedaxObjects ;

type
	TSignal = class( TMedaElement )
	private
		{ Private declarations }
       FPin : TMedaPin ;					{ originating Pin }
       FNet : TMedaNet ;
       FHere, FOldHere : TPoint ;
       FStart : TPoint ;
       FOnMouseDown : TMouseEvent ;
       FOnMouseMove : TMouseMoveEvent ;
       FOnMouseUp : TMouseEvent ;
       FPaintBox : TPaintBox ;
       FZoom : integer ;
       FPopup : TPopupMenu ;
       FDirection : set of TMedaDir ;
	protected
   	{ Protected declarations }
	public
		{ Public declarations }
		constructor Create( PaintBox : TPaintBox; Pin : TMedaPin ) ;
       procedure MouseMove( Sender: TObject; Shift: TShiftState; X, Y: Integer ) ;
       procedure MouseUp( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer ) ;
       procedure MouseDown( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer ) ;
//		destructor Destroy ; virtual ;
   published
		{ Published declarations }
  end;


implementation

constructor TSignal.Create( PaintBox : TPaintBox; Pin : TMedaPin ) ;
begin
	inherited Create( Pin.Box.Name + '-' + Pin.Name, etSignal ) ;
   FPin := Pin ;
   FStart.X := FPin.X ;
   FStart.Y := FPin.Y ;
   FDirection := FPin.Direction ;

   FPaintBox := PaintBox ;
   FPaintBox.PopupMenu := nil ;
	FZoom := FPaintBox.Tag ;
   FPopup := FPaintBox.PopupMenu ;
   FOnMouseDown := FPaintBox.OnMouseDown ;
	FOnMouseMove := FPaintBox.OnMouseMove ;
   FOnMouseUp := FPaintBox.OnMouseUp ;
	FPaintBox.OnMouseDown := MouseDown ;
	FPaintBox.OnMouseMove := MouseMove ;
	FPaintBox.OnMouseUp := MouseUp ;

	FOldHere.X := -1 ;
   FOldHere.Y := -1 ;

   { create a new net and pin the pin in the list of nodes }
	FNet := FPin.Box.Module.AddNet( Pin.Box.Name + '-' + Pin.Name ) ;
   FNet.AddPin( FPin ) ;
end ;

procedure TSignal.MouseMove( Sender: TObject; Shift: TShiftState; X, Y: Integer );
var
	hDC, nWidth : integer ;
begin
	with FPaintBox.Canvas do begin
   	hDC := Handle ;
       nWidth := Pen.Width ;
       FHere := Point( ( X + FZoom div 2 ) div FZoom, ( Y + FZoom div 2 ) div FZoom ) ;
       if ( FHere.X <> FOldHere.X ) or ( FHere.Y <> FOldHere.Y ) then begin
			if ( drEast in FDirection ) or ( drWest in FDirection ) then begin
		       	if FOldHere.X > -1 then
			       	PatBlt( hDC, FStart.X * FZoom, FStart.Y * FZoom, FOldHere.X * FZoom - FStart.X * FZoom, nWidth, DSTINVERT ) ;
       		PatBlt( hDC, FStart.X * FZoom, FStart.Y * FZoom, FHere.X * FZoom - FStart.X * FZoom, nWidth, DSTINVERT ) ;
           end else begin
		       	if FOldHere.Y > -1 then
			       	PatBlt( hDC, FStart.X * FZoom, FStart.Y * FZoom, nWidth, FOldHere.Y * FZoom - FStart.Y * FZoom, DSTINVERT ) ;
       		PatBlt( hDC, FStart.X * FZoom, FStart.Y * FZoom, nWidth, FHere.Y * FZoom - FStart.Y * FZoom, DSTINVERT ) ;
           end ;
           FOldHere := FHere ;
       end ;
   end ;
end ;

procedure TSignal.MouseDown( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer ) ;
var
	hDC, nWidth : integer ;
begin
	{ only line corners here }
	if Button <> mbRight then
   	Exit ;
	with FPaintBox.Canvas do begin
   	hDC := Handle ;
       nWidth := Pen.Width ;

		{ remove xor line }
		if ( drEast in FDirection ) or ( drWest in FDirection ) then begin
   		if FOldHere.X > -1 then
				PatBlt( hDC, FStart.X * FZoom, FStart.Y * FZoom, FOldHere.X * FZoom - FStart.X * FZoom, nWidth, DSTINVERT ) ;
       end else begin
	       	if FOldHere.Y > -1 then
		      	PatBlt( hDC, FStart.X * FZoom, FStart.Y * FZoom, nWidth, FOldHere.Y * FZoom - FStart.Y * FZoom, DSTINVERT ) ;
       end ;

       { draw this line and add to net object }

  		if ( FOldHere.X > -1 ) or ( FOldHere.Y > -1 ) then begin
			if ( drEast in FDirection ) or ( drWest in FDirection ) then begin
				MoveTo( FStart.X * FZoom, FStart.Y * FZoom ) ;
				LineTo( FOldHere.X * FZoom, FStart.Y * FZoom ) ;
           	FNet.AddLine( otHLine, FStart.X, FStart.Y, FOldHere.X ) ;
	       end else begin
				MoveTo( FStart.X * FZoom, FStart.Y * FZoom ) ;
				LineTo( FStart.X * FZoom, FOldHere.Y * FZoom ) ;
           	FNet.AddLine( otVLine, FStart.X, FStart.Y, FOldHere.Y ) ;
	       end ;
       end ;

  		{ turn 90 or 270 degrees }
		if drEast in FDirection then begin
			FDirection := [ drNorth, drSouth ] ;
           FStart.X := FOldHere.X ;
		end else if drWest in FDirection then begin
			FDirection := [ drNorth, drSouth ] ;
            FStart.X := FOldHere.X ;
		end else if drNorth in FDirection then begin
			FDirection := [ drWest, drEast ] ;
           FStart.Y := FOldHere.Y ;
		end else if drSouth in FDirection then begin
			FDirection := [ drWest, drEast ] ;
           FStart.Y := FOldHere.Y ;
       end ;

       FOldHere := Point( ( X + FZoom div 2 ) div FZoom, ( Y + FZoom div 2 ) div FZoom ) ;
		{ draw new xor line }
		if ( drEast in FDirection ) or ( drWest in FDirection ) then
	      	PatBlt( hDC, FStart.X * FZoom, FStart.Y * FZoom, FOldHere.X * FZoom - FStart.X * FZoom, nWidth, DSTINVERT )
       else
	      	PatBlt( hDC, FStart.X * FZoom, FStart.Y * FZoom, nWidth, FOldHere.Y * FZoom - FStart.Y * FZoom, DSTINVERT ) ;
   end ;
end ;

procedure TSignal.MouseUp( Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer ) ;
var
	hDC, nWidth : integer ;
   Target : TMedaElement ;
begin
	if Button <> mbLeft then
   	Exit ;

   Target := FPin.Box.Module.HitTest( X, Y, FZoom ) ;
	with FPaintBox.Canvas do begin
   	hDC := Handle ;
       nWidth := Pen.Width ;
		{ remove xor line }
		if ( drEast in FDirection ) or ( drWest in FDirection ) then begin
   		if FOldHere.X > -1 then
				PatBlt( hDC, FStart.X * FZoom, FStart.Y * FZoom, FOldHere.X * FZoom - FStart.X * FZoom, nWidth, DSTINVERT ) ;
       end else begin
	       	if FOldHere.Y > -1 then
		      	PatBlt( hDC, FStart.X * FZoom, FStart.Y * FZoom, nWidth, FOldHere.Y * FZoom - FStart.Y * FZoom, DSTINVERT ) ;
       end ;

		if ( Target <> nil ) and (( FOldHere.X > -1 ) or ( FOldHere.Y > -1 )) then begin
       	case Target.EType of
           	etPin:
               	FNet.AddPin( Target.Pin ) ;
               etNet:
               	begin
               		Target.Net.Join( FNet ) ;
                       FNet := Target.Net ;
                   end ;
               else
               	FDirection := [] ;
           end ;
			if ( drEast in FDirection ) or ( drWest in FDirection ) then begin
				MoveTo( FStart.X * FZoom, FStart.Y * FZoom ) ;
				LineTo( FOldHere.X * FZoom, FStart.Y * FZoom ) ;
	           	FNet.AddLine( otHLine, FStart.X, FStart.Y, FOldHere.X ) ;
			end else begin
				MoveTo( FStart.X * FZoom, FStart.Y * FZoom ) ;
				LineTo( FStart.X * FZoom, FOldHere.Y * FZoom ) ;
				FNet.AddLine( otVLine, FStart.X, FStart.Y, FOldHere.Y ) ;
			end ;
       end ;
   end ;
	FPaintBox.OnMouseDown := FOnMouseDown ;
	FPaintBox.OnMouseMove := FOnMouseMove ;
	FPaintBox.OnMouseUp := FOnMouseUp ;
   FPaintBox.PopupMenu := FPopup ;
   Free ;
end ;

end.
